﻿// 中文注释：该文件实现了ChannelScene类的成员函数，包括构造函数、析构函数和各种事件处理函数
#include "ChannelScene.h"
#include <QPointF>
#include <QDebug>

/**
 * @brief 构造函数：初始化场景元素
 * @param parent 父对象指针（用于内存管理）
 * 初始化时间游标、通道表格部件等核心元素，设置初始拖动状态为false，
 * 游标左右边界初始值为100像素，将时间游标添加到场景，
 * 创建通道表格部件的代理项（用于在QGraphicsScene中显示QWidget），
 * 启动50ms定时器（触发timerEvent实现自动移动）
 */
ChannelScene::ChannelScene(QObject *parent)
    :QGraphicsScene(parent),
      // 初始化时间游标对象
      m_timeCursor(new ChannelCursorItem),
      // 初始化通道表格部件对象
      m_chWidget(new ChannelTableItem),
      // 初始化拖动状态为未拖动
      m_isDragIng(false),
      // 初始化时间游标左边界为100像素
      m_timeCursorLeftBound(100),
      // 初始化时间游标右边界为100像素
      m_timeCursorRightBound(100)
{
    // 设置时间游标初始位置为左边界
    m_timeCursor->setX(m_timeCursorLeftBound);
    // 将时间游标项添加到场景
    addItem(m_timeCursor);
    // 创建通道表格部件的代理项（支持在图形场景中嵌入QWidget）
    m_chProxyWidget = addWidget(m_chWidget);
    // 启动150ms定时器（触发timerEvent实现自动移动逻辑）
    startTimer(150);
}

/**
 * @brief 析构函数：释放资源
 * 清理通道表格部件的代理项（QGraphicsProxyWidget需要显式释放）
 */
ChannelScene::~ChannelScene()
{
    // 若通道表格部件代理项存在，则释放其内存
    if(m_chProxyWidget)
    {
        delete m_chProxyWidget;
        // 将代理项指针置为nullptr，避免悬空指针
        m_chProxyWidget = Q_NULLPTR;
    }
}

/**
 * @brief 重置场景显示范围
 * @param rect 新的场景矩形区域（由ChannelView的resizeEvent调用）
 * 调整时间游标右边界（宽度-13像素用于预留边距），
 * 设置场景矩形范围，同步通道表格部件的位置和尺寸
 */
void ChannelScene::resetRect(const QRectF &rect)
{
    // 调整时间游标右边界，预留13像素边距
    m_timeCursorRightBound = rect.width() - 13;  
    // 设置场景显示范围
    setSceneRect(rect);                          
    // 同步通道表格部件的位置
    m_chProxyWidget->setPos(rect.x(), rect.y()); 
    // 同步通道表格部件的尺寸
    m_chProxyWidget->resize(rect.size());        
}

/**
 * @brief 更新通道记录
 * @param num 需要更新的通道数量（由ChannelView::updateChannelRecord调用）
 * 转发更新请求到通道表格部件（实际业务逻辑在ChannelTableItem中实现）
 */
void ChannelScene::updateChannelRecord(int num)
{
    // 转发更新通道记录的请求到通道表格部件
    m_chWidget->updateChannelRecord(num);
}

/**
 * @brief 定时器事件处理（每50ms触发）
 * @param event 定时器事件对象（用于区分不同定时器，此处仅一个定时器）
 * 非拖动状态时，时间游标自动右移10像素；超出右边界时重置到左边界，
 * 调用update()触发场景重绘
 */
void ChannelScene::timerEvent(QTimerEvent *event)
{
	Q_UNUSED(event);  // 忽略事件参数（仅一个定时器，不需要区分）
    // 拖动状态时暂停自动移动
    if(m_isDragIng)  
    {
        return;
    }
    // 每次右移10像素
    m_timeCursor->setX(m_timeCursor->x() + 10);  
    // 检查时间游标是否超出右边界
    if(m_timeCursor->pos().x() > m_timeCursorRightBound)  
    {
        // 若超出右边界，将时间游标重置到左边界
        m_timeCursor->setX(m_timeCursorLeftBound);  
    }
    // 触发场景重绘
    update();  
}

/**
 * @brief 鼠标按下事件处理
 * @param event 鼠标事件对象（包含位置、按键等信息）
 * 左键点击时间游标附近区域（x±10像素，y 0-20像素）时，标记为拖动状态
 */
void ChannelScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    // 仅处理左键点击事件
    if(event->button() == Qt::LeftButton)  
    {
        // 判断点击位置是否在时间游标附近（x±10像素，y 0-20像素）
        if(event->scenePos().x() > m_timeCursor->pos().x() - 10
                && event->scenePos().x() < m_timeCursor->pos().x()+10
                && event->scenePos().y() > 0 && event->scenePos().y() < 20)
        {
            // 若点击位置在游标附近，进入拖动状态
            m_isDragIng = true;  
        }
    }
}

/**
 * @brief 鼠标移动事件处理
 * @param event 鼠标事件对象（包含当前位置信息）
 * 拖动状态时，更新时间游标位置并限制在左右边界内，触发场景重绘
 */
void ChannelScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    // 仅在拖动状态时处理鼠标移动事件
    if(m_isDragIng)  
    {
        // 让时间游标跟随鼠标位置移动
        m_timeCursor->setX(event->scenePos().x());  
        // 检查时间游标是否超出左边界
        if(m_timeCursor->x() < m_timeCursorLeftBound)
        {
            // 若超出左边界，将时间游标设置到左边界位置
            m_timeCursor->setX(m_timeCursorLeftBound);
        }
        // 检查时间游标是否超出右边界
        if(m_timeCursor->x() > m_timeCursorRightBound)
        {
            // 若超出右边界，将时间游标设置到右边界位置
            m_timeCursor->setX(m_timeCursorRightBound);
        }
        // 触发场景重绘
        update();  
    }
}

/**
 * @brief 鼠标释放事件处理
 * @param event 鼠标事件对象（包含释放时的信息）
 * 结束拖动状态（无论是否在游标区域释放）
 */
void ChannelScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);  // 忽略事件参数（仅一个定时器，不需要区分）
    // 仅在拖动状态时处理鼠标释放事件
    if(m_isDragIng)  
    {
        // 退出拖动状态
        m_isDragIng = false;  
    }
}
